/**
 * 上海中赢金融信息服务有限公司
 * Copyright (c) 2016-2026 hmc,Inc.All Rights Reserved.
 */
package com.sys.midware.rdb.interceptor;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Random;

import org.apache.ibatis.binding.MapperProxy;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.ThrowsAdvice;
import org.springframework.aop.support.AopUtils;
import org.springframework.transaction.annotation.Transactional;

import com.sys.midware.logger.Logger;
import com.sys.midware.logger.LoggerFactory;
import com.sys.midware.rdb.annotation.DataSourceChoice;
import com.sys.midware.rdb.datasource.BDataSourceUtil;
import com.sys.midware.rdb.dbRouter.DBClusterRouter;
import com.sys.midware.rdb.dbRouter.DBClusterRouter.RouterSelector.Category;
import com.sys.midware.rdb.dbRouter.DBClusterRouter.RouterStrategy;

/**
 * 数据源选择拦截器
 * 
 * @author mobing@b5m.com
 * @see com.b5m.bocean.interceptor.DataSourceChoiceInterceptor
 * @version V0.0.1-SNAPSHOT, 2015-1-14 下午2:15:55
 * @description
 * 
 */
public class DataSourceChoiceInterceptor implements MethodBeforeAdvice, AfterReturningAdvice, ThrowsAdvice {

	private final static Logger LOG = LoggerFactory.getLogger(DataSourceChoiceInterceptor.class);
	private final static Random RDM = new Random(); 
	//是否需要进行数据源路由
	private boolean isSetDataSource;
	public DataSourceChoiceInterceptor() {
		LOG.info("初始化数据源选择拦截器");
	}

	@Override
	public void before(Method method, Object[] args, Object target) throws Throwable {
		String value = matchRouteSelector(method, target);
		if(value==null){
		    isSetDataSource =false;
		    
		}else{
		    isSetDataSource =true;
		}
		if(isSetDataSource){
		    DBClusterRouter.bindRouterStrategy(value, false);
	        BDataSourceUtil.setValidDataSource(value);
		}
		
		
	}

	@Override
	public void afterReturning(Object obj, Method methed, Object[] arg2,
			Object target) throws Throwable {
	    if(isSetDataSource){
    		if (!DBClusterRouter.clearRouter()) {
    			RouterStrategy rs = DBClusterRouter.getRouterStrategy();
    			BDataSourceUtil.setValidDataSource(rs.getKey());
    		}
	    }
	}

	public void afterThrowing(Exception ex) throws Throwable {
	    if(isSetDataSource){
    		if (!DBClusterRouter.clearRouter()) {
    			RouterStrategy rs = DBClusterRouter.getRouterStrategy();
    			BDataSourceUtil.setValidDataSource(rs.getKey());
    		}
	    }
	}
	
	private String matchRouteSelector(Method method, Object target){
		String value = null, name = method.getName();
		if ((value = DBClusterRouter.getRouterSelector(method)) != null) {
			return value;
		}
		//获取spring的代理对象
		Class<? extends Object> cls = AopUtils.getTargetClass(target) ;
		if(Proxy.isProxyClass(target.getClass())){
			Object targetObj=Proxy.getInvocationHandler(target);
			//如果是mybais的mapper代理则取mapper的代理对象，否则取spring的代理对象
			if(targetObj instanceof MapperProxy ){
				try {
					@SuppressWarnings("unchecked")
					MapperProxy<Object> mapperProxy = ((MapperProxy<Object>) Proxy.getInvocationHandler(target));
					Field field=    mapperProxy.getClass().getDeclaredField("mapperInterface");
					field.setAccessible(true);
					Object mapper = field.get(mapperProxy);
					cls=  Class.forName(mapper.toString().replaceAll("(interface|class)\\s*", ""));
				} catch (Exception e) {
					LOG.error("get mybatis mapper proxy object error!" + e.getMessage());
				}
			}
		}
		DataSourceChoice key = null;
		Category category = null;
		try {
			Method caller = cls.getMethod(name, method.getParameterTypes());
			if ((key = caller.getAnnotation(DataSourceChoice.class)) != null) {
				category = Category.METHOD;
				value = key.value();
			}
		} catch (Exception e) {
			if (LOG.isInfoEnabled()) {
				LOG.info("Method's datasource key not found");
			}
		}
		if (value == null) {
			key = cls.getAnnotation(DataSourceChoice.class);
			if (key != null && (value = key.value()) != null) {
				value = matchDataSource(name, value);
				category = Category.CLASS;
			} else {
			   return null;
//				throw new RDBException("BOcean datasource annotation key null");
			}
		}
		boolean ints = cls.getAnnotation(Transactional.class) != null;
		return DBClusterRouter.bindRouterSelector(method, category, value, ints);
	}
	
	private String matchDataSource(String method, String key) {
		if (method == null || key == null) {
			throw new NullPointerException("Parameter");
		}
		/*
		 * 主从映射改由mycat
		boolean matchMethod = method.toLowerCase().matches(
			"(.*)(get|query|load|select|find)(.*)"
		);
		if (matchMethod) {
			BOceanConfigVO oceanCfg = OceanConfigHolder.getOceanConfigurationVO();
			Map<String, DSClusterConfigVO> nodeMap = oceanCfg.getDataSourceNodeMap();
			if (nodeMap != null) {
				DSClusterConfigVO node = nodeMap.get(key);
				if (node == null || node.getMappingKey() == null) {
					throw new BOceanException(
						"检查bocean配置文件1、是否未设置数据源2、是否主从映射关系未配置,3、数据源节点Key是否配置错误"
					);
				}
				String[] slaver = node.getMappingKey();
				int leng = slaver.length, index = 0;
				if (leng > 1) {
					index = RDM.nextInt(leng);
				}
				return node.getMappingKey(index);
			}
		}
		*/
		return key;
	}
}